﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MMMaze
{
    public class Viewer3D<TWallContent>
    {
        public Viewer3D(Axises3D frontAxis, AxisDirection fontDirection)
        {
            if (frontAxis == Axises3D.Y)
            {
                throw new IndexOutOfRangeException("Cannot front to top");
            }

            //Functions.Add(RelativeDirection.Up, (Area3D<TWallContent> o) => (Area3D<TWallContent>)o.GetAxises(Axises3D.Y).GetNeighbor(AxisDirection.Negtive));
            Axises3DDic.Add(RelativeDirection.Up, Axises3D.Y);
            Axises3DDic.Add(RelativeDirection.Down, Axises3D.Y);
            Axises3DDic.Add(RelativeDirection.Front, frontAxis);
            Axises3DDic.Add(RelativeDirection.Back, frontAxis);

            AxisDirectionDic.Add(RelativeDirection.Up, AxisDirection.Negtive);
            AxisDirectionDic.Add(RelativeDirection.Down, AxisDirection.Positive);
            AxisDirectionDic.Add(RelativeDirection.Front, fontDirection);
            AxisDirectionDic.Add(RelativeDirection.Back, (AxisDirection)(-(int)fontDirection));

            var tmpLRAxe = frontAxis == Axises3D.X ? Axises3D.Z : Axises3D.X;
            var tmpleftDirection = frontAxis == Axises3D.X ?
                (fontDirection == AxisDirection.Positive ? AxisDirection.Negtive : AxisDirection.Positive)
                :
                (fontDirection == AxisDirection.Positive ? AxisDirection.Positive : AxisDirection.Negtive);

            Axises3DDic.Add(RelativeDirection.Left, tmpLRAxe);
            Axises3DDic.Add(RelativeDirection.Right, tmpLRAxe);

            AxisDirectionDic.Add(RelativeDirection.Left, (AxisDirection)(tmpleftDirection));
            AxisDirectionDic.Add(RelativeDirection.Right, (AxisDirection)(-(int)tmpleftDirection));



            //   fontDirection = (Area3D<TWallContent>  o) => (Area3D<TWallContent> )Position.GetAxises(frontAxis).GetNeighbor(fontDirection);
        }

        public IAxis<IAreaRoot> FrontAxis { get; private set; }

        public AxisDirection FontDirection { get; private set; }


        private Dictionary<RelativeDirection, Axises3D> Axises3DDic = new Dictionary<RelativeDirection, Axises3D>(6);
        private Dictionary<RelativeDirection, AxisDirection> AxisDirectionDic = new Dictionary<RelativeDirection, AxisDirection>(6);


        public void RenderMatrix(PanelMatrix pm, Area3D<TWallContent> standing, Action<TWallContent, Wall> RenderAction)
        {

            pm.Walls.Values.ToList().ForEach
                (o =>
                    {
                        o.CorePanel.Children.Clear();
                        o.CorePanel.Children.Add(o.CloseButton);

                    }
                );

            for (var i = pm.Layers.Count - 1; i >= 0; i--)
            {
                Area3D<TWallContent> tmproom = standing;
                var layer = pm.Layers[i];
               
                
                for (var l = 0; l < layer.LeftBladePanels.Count; l++)
                {
                    var w = layer.LeftBladePanels[l];
                    RenderAction.Invoke(GetWallContent(tmproom, RelativeDirection.Left), w);
                    tmproom = GetRelativeNeighbor (tmproom, RelativeDirection.Left);
                }

                for (var r = 0; r < layer.RightBladePanels.Count; r++)
                {
                    var w = layer.LeftBladePanels[r];
                    RenderAction.Invoke(GetWallContent(tmproom, RelativeDirection.Right ), w);
                    tmproom = GetRelativeNeighbor(tmproom, RelativeDirection.Right);
                }


               


            }

        }


        public Area3D<TWallContent> GetRelativeNeighbor(Area3D<TWallContent> position, RelativeDirection direction)
        {

          //  return Functions[direction].Invoke(position);
            return (Area3D<TWallContent>)position.GetAxises(Axises3DDic[direction]).GetNeighbor(AxisDirectionDic[direction]);

        }


        public TWallContent GetWallContent(Area3D<TWallContent> position, RelativeDirection direction)
        {

            //  return Functions[direction].Invoke(position);
            return (TWallContent)position.GetWallContent (Axises3DDic[direction] ,AxisDirectionDic[direction]);

        }

    }
    public enum RelativeDirection
    {
        Up,
        Down,
        Left,
        Right,
        Front,
        Back

    }
}
